package com.lge.simpleeventhandler.mainframe;

import com.lge.simpleeventhandler.Model;
import com.lge.simpleeventhandler.Resource;
import com.lge.simpleeventhandler.dom.JDOMParser;
import com.lge.simpleeventhandler.modelinfoboard.ModelInformationBoard;
import com.lge.simpleeventhandler.modelinfoboard.IModelInformationUpdateListener;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.util.ArrayList;

import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTabbedPane;
import javax.swing.KeyStroke;
import javax.swing.WindowConstants;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentEvent.EventType;
import javax.swing.filechooser.FileNameExtensionFilter;

public class MainFrame extends JFrame implements ActionListener, ItemListener, IModelInformationUpdateListener {
    private static final long serialVersionUID = 1L;

    private boolean fileOpend = false;
    private boolean fileChanged = false;

    private Container contentPane = null;
    private JFrame mainFrame = null;

    // Global Variables for NORTH Panel
    private JComboBox<String> modelComboBox = null;
    private JComboBox<String> projectComboBox = null;
    private JComboBox<String> countryComboBox = null;
    private JComboBox<String> operatorComboBox = null;
    
    private ArrayList<Model> modelList = null;
    
    private JPanel modelComboPanel = null;
    private JPanel projectComboPanel = null;

    // Global Variables for CENTER Panel
    private JTabbedPane centerPanel = null;

    private File modelXmlFile = null;

    // Constructors
    public MainFrame() throws HeadlessException {
        this(Resource.PROJECT_NAME_STRING);
    }

    public MainFrame(String title) throws HeadlessException {
        super(title);

        initComponent();
        toggleComboBoxPanel(true);

        pack();
        setResizable(false);

        setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent event) {
                if (fileChanged) {
                    int savePromptResult = JOptionPane.showConfirmDialog(mainFrame, Resource.EXIT_PROMPT_CONTENT_STRING, Resource.EXIT_PROMPT_TITLE_STRING, JOptionPane.YES_NO_CANCEL_OPTION);

                    if (savePromptResult == JOptionPane.CANCEL_OPTION) {
                        return;
                    } else if (savePromptResult == JOptionPane.YES_OPTION) {
                        saveFileWithChangingStatus("XML File", "xml");
                    } else if (savePromptResult == JOptionPane.NO_OPTION) {

                    }
                }

                mainFrame.dispose();
                System.exit(0);
            }
        });
        setVisible(true);
    }

    // Member Methods
    public void initComponent() {
        mainFrame = this;

        contentPane = getContentPane();
        contentPane.setLayout(new BorderLayout());

        contentPane.add(getWestPanel(), BorderLayout.WEST);
        contentPane.add(getEastPanel(), BorderLayout.EAST);
        contentPane.add(getNorthPanel(), BorderLayout.NORTH);
        contentPane.add(getSouthPanel(), BorderLayout.SOUTH);
        contentPane.add(getCenterPanel(), BorderLayout.CENTER);

        setJMenuBar(getCustomMenuBar());
    }

    public JComponent getWestPanel() {
        JComponent westPanel = new JPanel();

        return westPanel;
    }

    public JComponent getEastPanel() {
        JComponent eastPanel = new JPanel();

        return eastPanel;
    }

    public JComponent getNorthPanel() {
        JComponent northPanel = new JPanel(new GridLayout(1, 3));

        // SelectModel Panel
        JComponent selectModelPanel = new JPanel(new GridLayout(0, 1));

        JRadioButton modelRadioButton = new JRadioButton(Resource.MODEL_RADIO_STRING);
        modelRadioButton.setMnemonic(KeyEvent.VK_M);
        modelRadioButton.setActionCommand(Resource.MODEL_RADIO_STRING);
        modelRadioButton.setSelected(true);

        JRadioButton projectRadioButton = new JRadioButton(Resource.PROJECT_RADIO_STRING);
        projectRadioButton.setMnemonic(KeyEvent.VK_P);
        projectRadioButton.setActionCommand(Resource.PROJECT_RADIO_STRING);

        ButtonGroup radioButtonGroup = new ButtonGroup();
        radioButtonGroup.add(modelRadioButton);
        radioButtonGroup.add(projectRadioButton);

        // Add Action Listener
        modelRadioButton.addActionListener(this);
        projectRadioButton.addActionListener(this);

        selectModelPanel.add(modelRadioButton);
        selectModelPanel.add(projectRadioButton);

        // ComboBox Panel
        JPanel comboBoxPanel = new JPanel();

        modelComboPanel = new JPanel();

        modelComboBox = new JComboBox<String>();
        modelComboPanel.add(modelComboBox);

        projectComboPanel = new JPanel();

        projectComboBox = new JComboBox<String>();
        countryComboBox = new JComboBox<String>();
        operatorComboBox = new JComboBox<String>();
        
        projectComboBox.addItemListener(this);
        countryComboBox.addItemListener(this);
        operatorComboBox.addItemListener(this);

        projectComboPanel.add(projectComboBox);
        projectComboPanel.add(operatorComboBox);
        projectComboPanel.add(countryComboBox);

        comboBoxPanel.add(modelComboPanel);
        comboBoxPanel.add(projectComboPanel);

        // Serach Panel
        JPanel searchPanel = new JPanel();

        JButton searchButton = new JButton(Resource.SEARCH_BUTTON_STRING);
        searchButton.setActionCommand(Resource.SEARCH_BUTTON_STRING);
        searchButton.addActionListener(this);

        searchPanel.add(searchButton);

        northPanel.add(selectModelPanel);
        northPanel.add(comboBoxPanel);
        northPanel.add(searchPanel);

        return northPanel;
    }

    public JComponent getSouthPanel() {
        JComponent southPanel = new JPanel();

        return southPanel;
    }

    public JComponent getCenterPanel() {
        centerPanel = new JTabbedPane();

        // TODO: Add Model information Board
        centerPanel.addTab("+", new ModelInformationBoard(this));

        return centerPanel;
    }

    public void toggleComboBoxPanel(boolean modelVisible) {
        modelComboPanel.setVisible(modelVisible);
        projectComboPanel.setVisible(!modelVisible);
    }

    public JMenuBar getCustomMenuBar() {
        JMenuBar menuBar = new JMenuBar();

        JMenu fileMenu = new JMenu(Resource.FILE_MENU_STRING);
        fileMenu.setMnemonic(KeyEvent.VK_F);
        fileMenu.getAccessibleContext().setAccessibleDescription(Resource.FILE_MENU_DESCRIPTION_STRING);
        menuBar.add(fileMenu);

        JMenuItem openMenuItem = new JMenuItem(Resource.FILE_OPEN_MENU_STRING, KeyEvent.VK_O);
        openMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.ALT_MASK));
        openMenuItem.setActionCommand(Resource.FILE_OPEN_MENU_STRING);
        openMenuItem.addActionListener(this);
        fileMenu.add(openMenuItem);

        JMenuItem saveMenuItem = new JMenuItem(Resource.FILE_SAVE_MENU_STRING, KeyEvent.VK_S);
        saveMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.ALT_MASK));
        saveMenuItem.setActionCommand(Resource.FILE_SAVE_MENU_STRING);
        saveMenuItem.addActionListener(this);
        fileMenu.add(saveMenuItem);

        fileMenu.addSeparator();

        JMenuItem exitMenuItem = new JMenuItem(Resource.FILE_EXIT_MENU_STRING, KeyEvent.VK_X);
        exitMenuItem.setActionCommand(Resource.FILE_EXIT_MENU_STRING);
        exitMenuItem.addActionListener(this);
        fileMenu.add(exitMenuItem);

        return menuBar;
    }

    public void changeFileStatus() {
        if (!fileChanged) {
            if (fileOpend) {
                setTitle(Resource.PROJECT_NAME_STRING + " - " + modelXmlFile.getName() + " *");
            } else {
                setTitle(Resource.PROJECT_NAME_STRING + " - model.xml *");
            }
            
            fileChanged = true;
        }
    }

    public void saveFileWithChangingStatus(String fileDescription, String fileType) {
        if (fileChanged) {
            saveFile(fileDescription, fileType);
            setTitle(Resource.PROJECT_NAME_STRING + " - " + modelXmlFile.getName());
            fileChanged = false;
        }
    }
    
    public void newFile() {
        JDOMParser.loadDocumentWithFile(null);
        modelXmlFile = new File("newModels.xml");
        fileOpend = true;
        fileChanged = false;
    }

    public void importFile(String fileDescription, String fileType) {
        JFileChooser chooser = new JFileChooser(".");
        chooser.setFileFilter(new FileNameExtensionFilter(fileDescription + " (*." + fileType + ")", fileType));
        
        removeAllItems();
        
        int returnValue = chooser.showOpenDialog(MainFrame.this);
        if (returnValue == JFileChooser.APPROVE_OPTION) {
            modelXmlFile = chooser.getSelectedFile();
            setTitle(Resource.PROJECT_NAME_STRING + " - " + modelXmlFile.getName());
            fileOpend = true;
            
            JDOMParser.loadDocumentWithFile(modelXmlFile);
            
            modelList = JDOMParser.getModelList();
            for (Model model : modelList) {
                modelComboBox.addItem(model.getModelName());
                
                addItemWithoutDuplicatesInComboBox(projectComboBox, model.getModelProject());
            }
        } else if (returnValue == JFileChooser.CANCEL_OPTION) {
            
        } else {
            
        }
    }
    
    public void addItemWithoutDuplicatesInComboBox(JComboBox<String> comboBox, String item) {
        boolean exist = false;
        for (int i=0; i<comboBox.getItemCount(); i++) {
            if (comboBox.getItemAt(i).equals(item)) {
                exist = true;
            }
        }
        
        if (exist == false) {
            comboBox.addItem(item);
        }
    }
    
    public void saveFile(String fileDescription, String fileType) {
        JFileChooser chooser = new JFileChooser(".");
        chooser.setFileFilter(new FileNameExtensionFilter(fileDescription + " (*." + fileType + ")", fileType));
        
        int returnValue = chooser.showSaveDialog(MainFrame.this);
        if (returnValue == JFileChooser.APPROVE_OPTION) {
            modelXmlFile = chooser.getSelectedFile();
            JDOMParser.saveToFile(modelXmlFile);
        } else if (returnValue == JFileChooser.CANCEL_OPTION) {
            
        } else {
            
        }
    }
    
    public void removeAllItems() {
        modelComboBox.removeAllItems();
        projectComboBox.removeAllItems();
        operatorComboBox.removeAllItems();
        countryComboBox.removeAllItems();
        
        centerPanel.removeAll();
        centerPanel.addTab("+", new ModelInformationBoard(this));
    }
    
    public void loadModelInformation(Model model) {
        boolean isExistTab = false;
        
        for (int i=0; i<centerPanel.getTabCount(); i++) {
            if (centerPanel.getTitleAt(i).equals(model.getModelName())) {
                centerPanel.setSelectedIndex(i);
                isExistTab = true;
                break;
            }
        }
        
        if (isExistTab == false) {
            ModelInformationBoard modelInformationBoard = new ModelInformationBoard(model, this);
            centerPanel.addTab(model.getModelName(), modelInformationBoard);
            centerPanel.setSelectedComponent(modelInformationBoard);
        }
    }
    
    public void searchButtonPressed() {
        if (modelList != null) {
            for (Model model : modelList) {
                if (modelComboPanel.isVisible() && model.getModelName().equals(modelComboBox.getSelectedItem())) {
                    loadModelInformation(model);
                    break;
                }
                
                if (projectComboPanel.isVisible()) {
                    if (model.getModelProject().equals(projectComboBox.getSelectedItem()) && model.getModelOperator().equals(operatorComboBox.getSelectedItem()) && model.getModelCountry().equals(countryComboBox.getSelectedItem())) {
                        loadModelInformation(model);
                        break;
                    }
                }
            }
        }
    }
    

    // Callback Methods
    @Override
    public void actionPerformed(ActionEvent event) {
        if (event.getActionCommand().equals(Resource.MODEL_RADIO_STRING)) {
            toggleComboBoxPanel(true);
        } else if (event.getActionCommand().equals(Resource.PROJECT_RADIO_STRING)) {
            toggleComboBoxPanel(false);
        } else if (event.getActionCommand().equals(Resource.SEARCH_BUTTON_STRING)) {
            searchButtonPressed();
        } else if (event.getActionCommand().equals(Resource.FILE_OPEN_MENU_STRING)) {
            importFile("XML File", "xml");
        } else if (event.getActionCommand().equals(Resource.FILE_SAVE_MENU_STRING)) {
            saveFileWithChangingStatus("XML File", "xml");
        } else if (event.getActionCommand().equals(Resource.FILE_EXIT_MENU_STRING)) {
            dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
        }
    }

    @Override
    public void itemStateChanged(ItemEvent event) {
        if (event.getStateChange() == ItemEvent.SELECTED) {
            if (event.getSource() == projectComboBox) {
                operatorComboBox.removeAllItems();
                
                for (Model model : modelList) {
                    if (model.getModelProject().equals(projectComboBox.getSelectedItem())) {
                        addItemWithoutDuplicatesInComboBox(operatorComboBox, model.getModelOperator());
                    }
                }
            } else if (event.getSource() == operatorComboBox) {
                countryComboBox.removeAllItems();
                
                for (Model model : modelList) {
                    if (model.getModelOperator().equals(operatorComboBox.getSelectedItem())) {
                        addItemWithoutDuplicatesInComboBox(countryComboBox, model.getModelCountry());
                    }
                }
            }
        }
    }

    @Override
    public void modelInfoBoardSaveFinished(Model model) {
        modelComboBox.removeAllItems();
        projectComboBox.removeAllItems();
        operatorComboBox.removeAllItems();
        countryComboBox.removeAllItems();
        
        centerPanel.remove(0);
        centerPanel.insertTab("+", null, new ModelInformationBoard(this), "", 0);
        
        modelList = JDOMParser.getModelList();
        for (Model modelFromList : modelList) {
            modelComboBox.addItem(modelFromList.getModelName());
            
            addItemWithoutDuplicatesInComboBox(projectComboBox, modelFromList.getModelProject());
        }
        
        loadModelInformation(model);
    }

    @Override
    public void modelInfoTextChanged(DocumentEvent event) {
        if (event.getType() == EventType.INSERT) {
            if (!fileOpend) {
                newFile();
            }
            changeFileStatus();
        }
    }

    @Override
    public void modelInfoScheduleChanged() {
        if (!fileOpend) {
            newFile();
        }
        changeFileStatus();
    }
}